/****************************************************************************
*                                                                           *
* scdrawmanager.cpp 								                        *
*                                                                           *
* ALaRI 2008												                *
*                                                                           *
****************************************************************************/

/****************************************************************************
* Includes										                            *
****************************************************************************/
#include "drawmanager.h"
#include "drawstate.h"

/****************************************************************************
* CDrawState													 			*
****************************************************************************/
CDrawManager::CDrawManager(QPaintDevice *pPaintDevice, int& nWidth, int& nHeight):
	m_pDrawState(NULL),
	m_pSelectedShape(NULL),
	m_pPaintDevice(pPaintDevice),
	m_nWidth(nWidth),
	m_nHeight(nHeight),
	m_bImageChanged(true)
{
	assert(NULL != m_pPaintDevice);
	CDrawShape::setBoundingRect(nWidth, nHeight);
	// TODO rewrite this
	m_pen.setStyle(Qt::SolidLine);
	m_pen.setCapStyle(Qt::RoundCap);
	m_pen.setJoinStyle(Qt::RoundJoin);

	changeState(CDrawStateIdle::inst());
}

QString CDrawManager::uniqueShapeName(QString strName)
{
	QString strUnique;

	for (int nIndex = 0; ; ++nIndex)
	{
		strUnique = strName + QString::number(nIndex);
		if (indexOfShape(strUnique) == -1)
		break;
	}

	return strUnique;
}

int CDrawManager::indexOfShape(QString &strName) const
{
	for (int i = 0; i < m_qListShape.count(); ++i)
	{
		if (m_qListShape.at(i)->getName() == strName)
		return i;
	}
	
	return -1;
}

void CDrawManager::selectShape(const QPoint& rPoint)
{
	QList<CDrawShape *>::const_iterator it = m_qListShape.begin();
	while (it != m_qListShape.end())
	{
		if ((*it)->shapeHandle().contains(rPoint))
		{
			m_pSelectedShape = *it;
			emit updated();
			return;
		}
		*it++;
	}
}

CDrawManager::~CDrawManager()
{
	CDrawStateIdle::inst()->destroy();
	CDrawStateRect::inst()->destroy();
	CDrawStateLine::inst()->destroy();
	CDrawStateEllipse::inst()->destroy();
	CDrawStatePoint::inst()->destroy();
	removeAllShapes();
}

void CDrawManager::drawDemo()
{
	removeAllShapes();
	int nWidth = m_pen.width();

	m_pen.setWidth(5);
	QLine line(0, m_nHeight/2, m_nWidth/4, m_nHeight/2);
	addShape(new CDrawLine(line, m_pen.color(), m_pen.width()));

	line.setLine(m_nWidth/2, 0, m_nWidth/2, m_nHeight/4);
	addShape(new CDrawLine(line, m_pen.color(), m_pen.width()));

	line.setLine(m_nWidth/2, m_nHeight, m_nWidth/2, m_nHeight - m_nHeight/4);
	addShape(new CDrawLine(line, m_pen.color(), m_pen.width()));

	QRect rect(0, 0, m_nWidth - 1, m_nHeight - 1);
	addShape(new CDrawRect(rect, m_pen.color(), m_pen.width()));

	m_pen.setWidth(nWidth);
}

void CDrawManager::changeState(CDrawState *pDrawState)
{
	assert(NULL != pDrawState);
	if (m_pDrawState != pDrawState)
	{
		m_pDrawState = pDrawState;
		m_pSelectedShape = NULL;
	}
	emit updated();
}

void CDrawManager::startDrawRect()
{
	assert(NULL != m_pPaintDevice);
	changeState(CDrawStateRect::inst());
}

void CDrawManager::startDrawEllipse()
{
	assert(NULL != m_pPaintDevice);
	changeState(CDrawStateEllipse::inst());
}

void CDrawManager::startDrawLine()
{
	assert(NULL != m_pPaintDevice);
	changeState(CDrawStateLine::inst());
}

void CDrawManager::deleteCurrentShape()
{
	if (NULL != m_pSelectedShape)
	{
		if (m_pSelectedShape->type() != CDrawShape::ePoint)
		{
			// indicate that image has changed
			m_bImageChanged = true;
		}
		else emit pointAddedOrRemoved(static_cast<CSensorPoint*>(m_pSelectedShape), false);

		m_qListShape.removeOne(m_pSelectedShape);
		SafeFree(m_pSelectedShape);
		emit updated();
	}
}

void CDrawManager::startIdle()
{
	assert(NULL != m_pPaintDevice);
	changeState(CDrawStateIdle::inst());
}

void CDrawManager::startDrawPoint()
{
	assert(NULL != m_pPaintDevice);
	changeState(CDrawStatePoint::inst());
}

void CDrawManager::removeAllShapes()
{
	QList<CDrawShape *>::iterator it = m_qListShape.begin();

	while (it != m_qListShape.end())
	{
		if ((*it)->type() == CDrawShape::ePoint)
			emit pointAddedOrRemoved(static_cast<CSensorPoint*>(*it), false);
		SafeFree(*it);
		it++;
	}
	m_qListShape.clear();
	m_pSelectedShape = NULL;
	m_bImageChanged = true;
	emit updated();
}

void CDrawManager::reset()
{ 
	CDrawShape::setBoundingRect(m_nWidth, m_nHeight); 
	removeAllShapes(); 
	m_bImageChanged = true;
}

void CDrawManager::processEvent(QEvent *pEvent)
{
	assert(pEvent);
	m_pDrawState->processEvent(this, pEvent);
}

void CDrawManager::addShape(CDrawShape *pShape)
{
	// set unque mane for the shape
	pShape->setName(uniqueShapeName(pShape->getName())); 
	// add new shepe to the list 
	// TODO: check if such shape is already present
	m_qListShape.append(pShape);
	if (pShape->type() != CDrawShape::ePoint)
	{
		// indicate that image has changed
		m_bImageChanged = true;
	}
	else 
		emit pointAddedOrRemoved(static_cast<CSensorPoint*>(pShape), true);
	emit updated();
}

void CDrawManager::addShape(const QPoint& qPointFrom, const QPoint& qPointTo, int nType)
{
	CDrawShape::eType type = (CDrawShape::eType)nType; 

	CDrawShape *pShape = NULL; 
	switch (type)
	{
	case CDrawShape::eRectangle :
		pShape = new CDrawRect(QRect(qPointFrom, qPointTo), getPenColor(), getPenWidth());	
		break;
	case CDrawShape::eLine :
		pShape = new CDrawLine(QLine(qPointFrom, qPointTo), getPenColor(), getPenWidth());	
		break;
	case CDrawShape::eEllipse :
		pShape = new CDrawEllipse(QRect(qPointFrom, qPointTo), getPenColor(), getPenWidth());	
		break;
	case CDrawShape::ePoint :
		pShape = new CDrawPoint(QPoint(qPointFrom), Qt::blue, 5);	
		break;
	default:
		return; 
	}
	assert(NULL != pShape);
	if (NULL != pShape)
		addShape(pShape);
}

void CDrawManager::reshape(QPoint& rPoint, int nIndex /*= -1*/)
{
	CDrawShape *pShape;
	if (nIndex == -1)
		pShape = m_qListShape.last();
	else if (nIndex > 0 && nIndex <= m_qListShape.count())
		pShape = m_qListShape.at(nIndex);
	else return;
	pShape->reshape(rPoint);
	m_bImageChanged = true;
	emit updated();
}

void CDrawManager::redraw(QRegion& redrawRegion)
{
	QPainter painter(m_pPaintDevice);
	QPen pen = m_pen;

	if (false == m_qListShape.isEmpty())
	{
		QList<CDrawShape *>::const_iterator it = m_qListShape.begin();
		while (it != m_qListShape.end())
		{
			pen.setWidth((*it)->getWidth());
			pen.setColor((*it)->getColor());
			painter.setPen(pen);
			switch ((*it)->type())
			{
			case CDrawShape::eRectangle :
				painter.drawRect(*static_cast<CDrawRect *>(*it));
				break;
			case CDrawShape::eLine :
				painter.drawLine(*static_cast<CDrawLine *>(*it));
				break;
			case CDrawShape::eEllipse :
				painter.drawEllipse(*static_cast<CDrawEllipse *>(*it));
				break;
			case CDrawShape::ePoint :
				painter.drawPoint(*static_cast<CDrawPoint *>(*it));
				break;
			}

			if (m_pDrawState->state() == CDrawState::eIdleState)
			{
				// paint the shape handle
				pen.setColor(Qt::black);
				pen.setWidth(m_pSelectedShape != *it ? 1 : 2);
				painter.setPen(pen);
				QRect handle = (*it)->shapeHandle();
				painter.drawRect(handle);
				if ((*it)->type() == CDrawShape::ePoint)
					painter.drawText(handle, Qt::AlignCenter, (*it)->name());
				painter.setPen(m_pen);
			}
			it++;
		}
	}
	painter.end();
}

QImage CDrawManager::getImage() const
{
	QImage image(m_nWidth, m_nHeight, QImage::Format_RGB32);
	image.fill(m_colorBackground.rgb());
	QPainter painter(&image);
	QPen pen(Qt::SolidLine);
	pen.setCapStyle(Qt::RoundCap);
	pen.setJoinStyle(Qt::RoundJoin);

	if (false == m_qListShape.isEmpty())
	{
		QList<CDrawShape *>::const_iterator it = m_qListShape.begin();
		while (it != m_qListShape.end())
		{
			pen.setWidth((*it)->getWidth());
			pen.setColor((*it)->getColor());
			painter.setPen(pen);
			switch ((*it)->type())
			{
			case CDrawShape::eRectangle :
				painter.drawRect(*static_cast<CDrawRect*>(*it));
				break;
			case CDrawShape::eLine :
				painter.drawLine(*static_cast<CDrawLine*>(*it));
				break;
			case CDrawShape::eEllipse :
				painter.drawEllipse(*static_cast<CDrawEllipse*>(*it));
				break;
			}
			*it++;
		}
	}
	return image;
}

/****************************************************************************
* End of file																*
****************************************************************************/